"""
Agent核心技能提示词： 本文件中的提示词描述了每个节点的能力，可以进一步扩展放到各自的.md文件中。
"""
from typing import List, Dict, Union, Any, Optional, Callable
import os
import json
class PromptManager:
    """
    集中管理所有提示词。
    """

    def get_perception_prompt(self) -> str:
        """生成用于理解用户初始意图的提示词。"""
        return """
        你的任务是分析用户的输入，并提取其完整、明确的目标。
        将这个目标总结成一个清晰、可执行的、按步骤编号的列表。
        你的输出必须直接是这个列表，不要包含任何前导或结尾的解释。

        例如:
        - 用户输入: "帮我查查根目录下 paper.pdf 这篇论文的第二页写了啥"
        - 你的输出: 
        1. 查找根目录下的 'paper.pdf' 文件。
        2. 读取并返回 'paper.pdf' 文件第二页的内容。

        - 用户输入: "100的平方根乘以5是多少？"
        - 你的输出: 
        1. 计算100的平方根。
        2. 将上一步的结果乘以5。
        """

    def get_planning_prompt(self, goal: str, tools_description: str) -> str:
        """
        生成用于将用户目标分解为可执行计划的提示词。
        """
        return f"""
        你是一位顶级的AI项目规划师和系统架构师。你的任务是分析用户的最终目标和可用的工具集，然后将其分解为一个详细、有序、可执行的子任务计划。

        **最终目标 (User Goal):**
        {goal}

        **可用工具 (Available Tools):**
        {tools_description}

        **你的任务与规则:**
        1.  **分解任务**: 将用户的复杂目标分解成一系列更小、更简单的原子步骤。每个步骤都应该是一个清晰、独立的子任务。
        2.  **工具可行性**: 确保你规划的每一步都是可以通过一个或多个可用工具来现实地完成的。不要幻想不存在的工具。
        3.  **逻辑顺序**: 安排这些步骤的执行顺序，确保它们符合逻辑。如果步骤之间存在依赖关系，请在计划中体现出来。
        4.  **清晰描述**: 为每个步骤提供一个简洁明了的描述，说明该步骤需要完成什么。
        5.  **语言一致性**: 你的计划描述必须使用与用户目标相同的语言（例如，如果目标是中文，计划也必须是中文）。

        **输出格式:**
        你必须严格按照以下JSON格式输出你的计划。不要包含任何额外的解释或文本。

        {{
            "plan": [
                {{
                    "step_id": 1,
                    "description": "第一步的描述...",
                    "estimated_tools": ["tool_name_1", "tool_name_2"],
                    "dependencies": []
                }},
                {{
                    "step_id": 2,
                    "description": "第二步的描述，它依赖于第一步的结果...",
                    "estimated_tools": ["tool_name_3"],
                    "dependencies": [1]
                }}
            ]
        }}

        现在，请根据用户的最终目标和可用工具，生成你的JSON计划。
        """

    def get_deliberation_prompt(self, goal: str, full_plan: str, cur_step: Dict, history: Union[List[tuple], List[str]],
                                tools_description: str,
                                experience_hint: str = "") -> str:
        """
        生成 ReAct 循环中的“思考”提示词。du
        支持压缩历史和经验提示，防止上下文崩溃。
        """
        history_str = ""
        for thought, action, observation in history[-1:]:  # 只展示最近2条历史
            action_str = json.dumps(action, ensure_ascii=False, indent=2)
            history_str += f"Thought: {thought}\nAction: {action_str}\nObservation: {observation}\n---\n"

        experience_section = f"**经验提示:**\n{experience_hint if experience_hint else '暂无相关经验'}\n" if experience_hint else ""

        return f"""
        假设你是一个能够解决复杂问题的MIT工程学教授。你的任务是接收用户的请求，并通过一个“思考->行动->观察”的循环来完成它。
        现在，你已经接收到了流程专家针对这个问题的分解，你需要必须严格遵守以下规则和工作流程，针对 **你的当前任务 (Current Task):**构建思考和行动规划。

        **你的最终目标是:** {goal}
        
        **完整的行动计划:**
        {full_plan} 

        **你的当前任务 (Current Task):**
        步骤 {cur_step["step_id"]}: {cur_step["description"]} 
        **请注意：你的所有思考和行动都必须严格围绕完成“当前任务”展开。**

        **可用工具:**
        你只能使用以下定义的工具。不要编造任何不存在的工具。
        {tools_description}

        **思考与行动历史 (上1步):**
        {history_str if history_str else "无 (这是第一步)"}
        {experience_section}
        **你的任务:**
        1.  **思考 (Thought):** 基于你的“当前任务”和历史记录，清晰地分析现状，并制定出下一步具体的行动计划。如果之前的尝试失败了，分析原因并调整策略。
        2.  **行动 (Action):** 选择一个最合适的工具来执行你的计划。

       **特殊情况:**
        - 如果你认为当前任务仅通过思考和总结就能完成（例如，历史观察中已有足够信息），或者你发现缺少完成当前任务的关键工具，请使用 `finish` 工具，并在 `args` 的 `answer` 字段中说明情况或提供总结。
        - 如果缺少工具，可以在`thought`中输出"工具不足，无法完成当前步骤。"然后调用`finish`。

        **输出格式:**
        你的输出必须是一个严格的JSON对象，格式如下：
        {{
            "thought": "这里是你对当前任务的分析和下一步行动的计划...",
            "action": {{
                "name": "<tool_name>",
                "args": {{ "arg1": "value1" }}
            }}
        }}

        现在，请生成你的“思考”和“行动”。 
        """

    def get_judgment_prompt(
            self,
            goal: str,
            full_plan: str,
            cur_step: Dict,
            last_observation: str,
            history: List[tuple],
            experience_hint: str = ""
    ) -> str:
        """
        (全新重构) 用于任务进度评估的提示词。输出明确的控制指令。
        """
        # 格式化最近的历史记录以提供上下文
        history_str = ""
        for thought, action, observation in history[-3:]: # 最近3条
            action_str = json.dumps(action, ensure_ascii=False)
            history_str += f"Thought: {thought}\nAction: {action_str}\nObservation: {observation}\n---\n"

        return f"""
        你是一个智能体流程的“决策核心”。你的职责是评估上一步行动的结果，并决定整个流程的下一步走向。

        **最终总目标:** {goal}

        **完整的行动计划:**
        {full_plan}

        **刚刚执行的任务:**
        步骤 {cur_step["step_id"]}: {cur_step["description"]}

        **刚刚得到的观察结果 (Observation):**
        {last_observation}

        **相关历史记录:**
        {history_str}

        **经验提示:**
        {experience_hint if experience_hint else "暂无相关经验"}

        **你的决策任务:**
        根据以上所有信息，选择一个最符合当前情况的决策，并以严格的JSON格式输出。

        **决策选项:**
        1.  `CURRENT_STEP_COMPLETE`: 当前步骤已成功完成。
            - **何时选择**: 观察结果明确表明当前步骤的目标已达成。
            - **需要提供**: `next_step_id`，即计划中的下一个步骤ID。
        2.  `OVERALL_GOAL_COMPLETE`: 整个最终目标已经完成/如果当前是最后一步，可以结束。
            - **何时选择**: 观察结果已经包含了回答最终总目标所需的所有信息，无需再执行后续步骤。
            - **需要提供**: `final_answer`，即对最终总目标的完整回答。
        3.  `RETRY_STEP`: 当前步骤失败，但值得重试。
            - **何时选择**: 观察结果是错误信息（如文件未找到、API调用失败），但通过改变工具参数或策略可能成功。
            - **需要提供**: `reasoning`，简要说明为什么需要重试以及建议的调整方向（这将帮助下一轮的Deliberation）。
        4.  `PLAN_FAILURE`: 计划失败，无法继续。
            - **何时选择**: 遇到无法解决的根本性问题（如连续重试失败、缺少关键工具、计划本身存在逻辑错误）。
            - **需要提供**: `reasoning`，清晰地解释失败的原因。

        **输出格式 (严格JSON):**
        你必须从以下四种格式中选择一种进行输出，不能添加任何额外文本。

        // 格式1: 当前步骤完成
        {{
            "decision": "CURRENT_STEP_COMPLETE",
            "reasoning": "已成功读取文件内容，满足步骤要求。",
            "next_step_id": <下一个步骤的整数ID，注意禁止虚构不存在的步骤>
        }}

        // 格式2: 整体目标完成
        {{
            "decision": "OVERALL_GOAL_COMPLETE",
            "reasoning": "观察结果已包含最终答案，无需继续执行计划。",        
        }}

        // 格式3: 重试当前步骤
        {{
            "decision": "RETRY_STEP",
            "reasoning": "文件未在指定路径找到，将尝试在根目录搜索。"
        }}

        // 格式4: 计划失败
        {{
            "decision": "PLAN_FAILURE",
            "reasoning": "缺少解析PDF文件的工具，无法完成任务。"
        }}

        现在，请做出你的决策。
        """

    def get_finalize_prompt(
            self,
            goal: str,
            final_result: str # 可能是答案，也可能是错误信息
    ) -> str:
        """用于最后的结果生成或总结。"""
        # 这个Prompt设计得很好，保持原样，仅修改输入参数名以更清晰
        return f"""
        你是一位MIT的工程学教授，负责对智能体的工作进行最终审核和润色。
        
        **智能体的最终输出:**
        {final_result}

        你的任务是：
        审查智能体的最终输出，检查语法以及逻辑，并进行润色。      

        现在，请生成你的最终回复。
        """

    def _compress_history_for_prompt(self, history: List[tuple]) -> str:
        """
        压缩历史记录，避免提示词过长
        下一次课程中，可以替换为更复杂的摘要或向量化检索方法。
        """
        if not history:
            return ""

        # 如果历史记录很短，直接返回
        if len(history) <= 3:
            return "\n".join([
                f"Thought: {thought}\nAction: {json.dumps(action)}\nObservation: {obs}"
                for thought, action, obs in history
            ])

        # 压缩策略：保留关键信息
        compressed = []

        # 保留第一步
        thought, action, obs = history[0]
        compressed.append(f"开始: Thought: {thought}\nAction: {json.dumps(action)}\nObservation: {obs[:500]}...")

        # 保留失败步骤
        for i, (thought, action, obs) in enumerate(history[1:-1], 1):
            if "错误" in str(obs).lower() or "失败" in str(obs).lower():
                compressed.append(
                    f"步骤{i}: Thought: {thought[:30]}...\nAction: {json.dumps(action)}\nObservation: {obs[:50]}...")

        # 保留最后一步
        thought, action, obs = history[-1]
        compressed.append(f"最新: Thought: {thought}\nAction: {json.dumps(action)}\nObservation: {obs}")

        return "\n".join(compressed)
